package org.linlinjava.litemall.admin.aspect;


import org.apache.commons.logging.Log;
import org.apache.commons.logging.LogFactory;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.aspectj.lang.reflect.MethodSignature;
import org.linlinjava.litemall.admin.annotation.IgnoreVendorIdConditionWhenAdmin;
import org.linlinjava.litemall.admin.util.CommonUtil;
import org.springframework.stereotype.Component;

import java.lang.reflect.Method;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;

@Aspect
@Component
public class IgnoreVendorIdConditionAspect {
    public static ThreadLocal<Boolean> isIgnoreVendorIdCondition = new ThreadLocal<>();

    // 定义切点Pointcut
    @Pointcut("execution(public * org.linlinjava.litemall.admin..*.*(..))")
    public void excudeService() {
    }

    @Around("excudeService()")
    public Object doAround(ProceedingJoinPoint pjp) throws Throwable {
        //拦截的对象
        Object target = pjp.getTarget();
        //拦截的方法名称
        String methodName = pjp.getSignature().getName();
        //拦截的方法参数
        Object[] args = pjp.getArgs();
        //拦截的放参数类型
        Class[] parameterTypes = ((MethodSignature)pjp.getSignature()).getMethod().getParameterTypes();
        Method m = null;
        try {
            //通过反射获得拦截的method
            m = target.getClass().getMethod(methodName, parameterTypes);
            //如果是桥则要获得实际拦截的method
            if(m.isBridge()){
                for(int i = 0; i < args.length; i++){
                    //获得泛型类型
                    Class genClazz = getSuperClassGenricType(target.getClass());
                    //根据实际参数类型替换parameterType中的类型
                    if(args[i].getClass().isAssignableFrom(genClazz)){
                        parameterTypes[i] = genClazz;
                    }
                }
                //获得parameterType参数类型的方法
                m = target.getClass().getMethod(methodName, parameterTypes);
            }
        } catch (SecurityException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

        //类或者当前方法有IgnoreVendorIdConditionAsAdmin注解且当前用户是管理员，就设置标志位
        if(null != m.getAnnotation(IgnoreVendorIdConditionWhenAdmin.class) ||
            null != target.getClass().getAnnotation(IgnoreVendorIdConditionWhenAdmin.class)) {

            if(CommonUtil.isSysAdmin()) {
                isIgnoreVendorIdCondition.set(true);
            }
        }

        Object result = pjp.proceed();

        //处理完成后，移除标志
        isIgnoreVendorIdCondition.remove();
        return result;
    }

    /**
     * 通过反射,获得指定类的父类的泛型参数的实际类型. 如DaoSupport<Buyer>
     *
     * @param clazz
     *            clazz 需要反射的类,该类必须继承范型父类
     * @return 范型参数的实际类型, 如果没有实现ParameterizedType接口，即不支持泛型，所以直接返回
     *         <code>Object.class</code>
     */
    @SuppressWarnings("unchecked")
    public static Class getSuperClassGenricType(Class clazz) {

        Type genType = clazz.getGenericSuperclass();// 得到泛型父类

        // 如果没有实现ParameterizedType接口，即不支持泛型，直接返回Object.class
        if (!(genType instanceof ParameterizedType)) {

            return Object.class;
        }

        // 返回表示此类型实际类型参数的Type对象的数组,数组里放的都是对应类型的Class, 如BuyerServiceBean extends
        // DaoSupport<Buyer,Contact>就返回Buyer和Contact类型
        Type[] params = ((ParameterizedType) genType).getActualTypeArguments();

        if (!(params[0] instanceof Class)) {

            return Object.class;
        }
        return (Class) params[0];
    }
}